package com.tn.rtdata.performance;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;

import com.tn.rtdata.DataEvent;
import com.tn.rtdata.DataListener;
import com.tn.rtdata.DataSource;
import com.tn.rtdata.EventDrivenDataSource;
import com.tn.rtdata.Session;

/**
 * Represents a client with it's own application context and lifecycle.
 */
public class Client
{
  private ClassPathXmlApplicationContext applicationContext;
  private ClientDef clientDef;
  private Date created;
  private List<DataListener<Client>> dataListeners;
  private long updateCount;

  /**
   * Creates a new <code>Client</code> initialized with the <code>clientDef</code>.
   */
  public Client(ClientDef clientDef)
  {
    this.clientDef = clientDef;
    this.created = new Date();
    this.dataListeners = new ArrayList<DataListener<Client>>();
    this.applicationContext = new ClassPathXmlApplicationContext(clientDef.getApplicationContextLocation());
    this.applicationContext.start();

    //noinspection unchecked
    this.applicationContext.getBean(DataSource.class).addDataListener(
      new DataListener()
      {
        @Override
        public void dataEvent(DataEvent dataEvent)
        {
          if (DataEvent.Type.UPDATE.equals(dataEvent.getType()))
          {
            updateCount++;
            fireDataListeners();
          }
        }
      }
    );
  }

  /**
   * Returns the created timestamp.
   */
  public Date getCreated()
  {
    return created;
  }

  /**
   * Returns the display name.
   */
  public String getDisplayName()
  {
    return clientDef.getDisplayName();
  }

  /**
   * Returns the fill name.
   */
  public String getFillName()
  {
    return applicationContext.getBean(EventDrivenDataSource.class).getFillName();
  }

  /**
   * Returns the session id.
   */
  public String getSessionId()
  {
    return applicationContext.getBean(Session.class).getId();
  }

  /**
   * Returns the client type.
   */
  public String getType()
  {
    return clientDef.getType();
  }

  /**
   * Returns the update count.
   */
  public Long getUpdateCount()
  {
    return updateCount;
  }

  /**
   * Stops this <code>Client</code>.
   */
  public void stop()
  {
    this.applicationContext.stop();
    this.applicationContext.destroy();
  }

  /**
   * Adds the <code>dataListener</code>.
   */
  public void addDataListener(DataListener<Client> dataListener)
  {
    dataListeners.add(dataListener);
  }

  /**
   * Adds the <code>dataListener</code>.
   */
  public void removeDataListener(DataListener<Client> dataListener)
  {
    dataListeners.remove(dataListener);
  }

  /**
   * Fires the <code>dataEvent</code> to the data event listeners.
   */
  private void fireDataListeners()
  {
    for (DataListener dataListener : dataListeners)
    {
      //noinspection unchecked
      dataListener.dataEvent(new DataEvent<Client>(DataEvent.Type.UPDATE, this, this));
    }
  }
}
